#pragma once

#include <queue>
#include <thread>

#include "msg.h"

/**
 * 必须加 extern "C" {...}, 否则会提示找不到.
 * 真坑啊, 浪费一个小时...
 */
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

using namespace std;

/**
 * service 的写法要符合一个规范.
 * skynet 对服务(Actor)的设计是: 一定有固定的方法签名, 方面 work thread 调用它处理消息以及 orchestrator 初始化和管理它.
 */

class service
{
public:
    // 唯一 id
    uint32_t id;
    // 类型描述
    shared_ptr<string> type;
    // 是否正在退出
    bool is_existing = false;
    // 消息队列和锁
    queue<shared_ptr<base_msg>> msg_queue;
    pthread_spinlock_t msg_queue_lock;

private:
    // lua virtual state
    lua_State *luastate;

public:
    // 标记位, 表示是否在全局队列中
    bool is_in_global_queue = false;
    pthread_spinlock_t is_in_global_queue_lock;
    void set_in_global(bool is_in);

public:
    // 构造函数和析构函数
    service();
    ~service();

    // 回调函数(服务逻辑)
    void on_init();
    void on_msg(shared_ptr<base_msg> msg);
    void on_exit();

    // 插入消息
    void push_msg(shared_ptr<base_msg> msg);
    bool process_msg();
    void process_msgs(int max);

private:
    // 取出一条消息
    shared_ptr<base_msg> pop_msg();

private:
    // 处理各类消息
    void on_service_msg(shared_ptr<service_msg> msg);
    void on_accept_msg(shared_ptr<socket_accept_msg> msg);
    void on_rw_msg(shared_ptr<socket_rw> msg);

    void on_socket_date(int fd, const char *buff, int len);
    void on_socket_write(int fd);
    void on_socket_close(int fd);
};